package client

import (
	"context"
	"encoding/json"
	"fmt"
	"google.golang.org/grpc/resolver"
	"log"
	"longmen/server/pkg/common/app/etcd"
	"reflect"
	"time"
)

type discoveryResolver struct {
	w    *etcd.Watcher
	cons resolver.ClientConn
	ins  []*etcd.ServiceInstance

	ctx    context.Context
	cancel context.CancelFunc
}

func (r *discoveryResolver) watch() {
	for {
		select {
		case <-r.ctx.Done():
			return
		default:
		}
		ins, err := r.w.Next()
		if err != nil {
			log.Printf("[resolver] Failed to watch discovery endpoint: %v \n", err)
			time.Sleep(time.Second)
			continue
		}
		if !reflect.DeepEqual(r.ins, ins) {
			if len(ins) == 0 && len(r.ins) == 0 {
				continue
			}
			r.ins = ins
			inBytes, _ := json.MarshalIndent(&ins, "", "    ")
			fmt.Printf("服务变动: %+s \n", inBytes)
		}
		r.update(ins)
	}
}

func (r *discoveryResolver) update(ins []*etcd.ServiceInstance) {
	addrs := make([]resolver.Address, 0)
	endpoints := make(map[string]struct{})
	for _, in := range ins {
		if in.Endpoints == "" {
			continue
		}
		if _, ok := endpoints[in.Endpoints]; ok {
			continue
		}
		endpoints[in.Endpoints] = struct{}{}
		addr := resolver.Address{
			Addr:       in.Endpoints,
			ServerName: in.Name,
		}
		addrs = append(addrs, addr)
	}
	if len(addrs) == 0 {
		log.Printf("[resolver] Zero endpoint found,refused to write, instances: %+v \n", ins)
		return
	}
	err := r.cons.UpdateState(resolver.State{Addresses: addrs})
	if err != nil {
		log.Printf("[resolver] update state is error: %+v \n", err.Error())
		return
	}
}

func (r *discoveryResolver) Close() {
	r.cancel()
	err := r.w.Stop()
	if err != nil {
		log.Printf("[resolver] failed to watch top: %s \n", err)
	}
}

func (r *discoveryResolver) ResolveNow(options resolver.ResolveNowOptions) {}
